#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Web服务
Web Service

基于Flask的Web应用服务，提供：
- RESTful API接口
- 实时视频流
- Web界面
- 系统状态监控
"""

import cv2
import numpy as np
import logging
import time
import threading
from pathlib import Path
from flask import Flask, Response, jsonify, request, render_template
from typing import Optional

project_root = Path(__file__).parent.parent.parent

from ..core import YOLO11_FaceDetect, GimbalController, DataStore, PerformanceMonitor
from ..core.tracking import CoordinateCalculator
from ..config.settings import Settings
from ..api.routes import register_api_routes

logger = logging.getLogger("WebService")


class WebService:
    """Web应用类，提供视频流和API服务"""
    
    def __init__(self, model: YOLO11_FaceDetect, config: Settings):
        """
        初始化Web应用

        Args:
            model: YOLO人脸检测模型实例
            config: 配置对象
        """
        # 设置模板和静态文件路径
        template_dir = project_root / "face_tracker_mcp" / "web" / "templates"
        static_dir = project_root / "face_tracker_mcp" / "web" / "static"

        self.app = Flask(__name__,
                        template_folder=str(template_dir),
                        static_folder=str(static_dir))
        self.model = model
        self.config = config
        
        # 摄像头配置
        self.camera_path = config.camera.device_path
        self.width = config.camera.width
        self.height = config.camera.height
        
        # 设置摄像头
        self.setup_camera()
        
        # 创建性能监控器
        self.performance_monitor = PerformanceMonitor()
        
        # 创建数据存储管理器
        self.data_store = DataStore()
        
        # 初始化云台控制器
        logger.info("正在初始化云台控制器...")
        self.gimbal_controller = None
        self.coord_calculator = None
        try:
            self.gimbal_controller = GimbalController(config)
            if self.gimbal_controller.connect():
                logger.info("✓ 云台控制器初始化成功")

                # 初始化坐标计算器
                self.coord_calculator = CoordinateCalculator(
                    frame_width=self.width,
                    frame_height=self.height,
                    tracking_config=self.config.tracking,
                )
                logger.info("✓ 坐标计算器初始化成功")
            else:
                logger.warning("⚠️ 云台连接失败")
        except Exception as e:
            logger.warning(f"⚠️ 云台控制器初始化失败: {e}")
            logger.warning("将在无云台模式下运行")
        
        # 追踪状态
        self.tracking_enabled = False
        self.tracking_target_id = None
        
        # 线程控制
        self.running = False
        self.video_thread = None
        self.lock = threading.Lock()
        
        # 设置路由
        self.setup_routes()
        
        logger.info("Web服务初始化完成")
    
    def setup_camera(self):
        """设置摄像头"""
        try:
            logger.info(f"正在初始化摄像头: {self.camera_path}")
            self.camera = cv2.VideoCapture(self.camera_path)
            
            if not self.camera.isOpened():
                raise Exception(f"无法打开摄像头: {self.camera_path}")
            
            # 设置摄像头参数
            self.camera.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
            self.camera.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
            self.camera.set(cv2.CAP_PROP_FPS, self.config.camera.fps)
            
            # 验证设置
            actual_width = int(self.camera.get(cv2.CAP_PROP_FRAME_WIDTH))
            actual_height = int(self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
            actual_fps = self.camera.get(cv2.CAP_PROP_FPS)
            
            logger.info(f"✓ 摄像头初始化成功")
            logger.info(f"分辨率: {actual_width}x{actual_height}, FPS: {actual_fps}")
            
        except Exception as e:
            logger.error(f"摄像头初始化失败: {e}")
            self.camera = None
            raise
    
    def setup_routes(self):
        """设置路由"""
        
        @self.app.route('/')
        def index():
            """主页面"""
            try:
                gimbal_status = self.gimbal_controller.get_status() if self.gimbal_controller else None

                if not gimbal_status or not gimbal_status['connected']:
                    # 云台未连接，返回禁用页面
                    return render_template('disabled.html',
                                         tracking_state='Disabled',
                                         pan_angle=self.config.gimbal.init_pan_angle,
                                         tilt_angle=self.config.gimbal.init_tilt_angle,
                                         pan_pin=self.config.gimbal.pan_pin,
                                         tilt_pin=self.config.gimbal.tilt_pin)
                else:
                    # 云台已连接，返回正常页面
                    current_angles = gimbal_status['current_angles']
                    tracking_state = "ON" if self.tracking_enabled else "OFF"

                    return render_template('index.html',
                                         pan_pin=self.config.gimbal.pan_pin,
                                         tilt_pin=self.config.gimbal.tilt_pin,
                                         initial_pan=round(current_angles['pan'], 1),
                                         initial_tilt=round(current_angles['tilt'], 1),
                                         tracking_state=tracking_state)
            except Exception as e:
                logger.error(f"主页面渲染错误: {e}")
                # 返回包含必要JavaScript变量的错误页面
                return f"""
                <html>
                <head>
                    <title>智能人脸追踪系统</title>
                    <script>
                        // 设置默认的引脚变量，避免JavaScript错误
                        window.PAN_PIN = {self.config.gimbal.pan_pin};
                        window.TILT_PIN = {self.config.gimbal.tilt_pin};
                    </script>
                </head>
                <body>
                    <h1>智能人脸追踪系统</h1>
                    <p>系统正在初始化，请稍后刷新页面...</p>
                    <p>错误信息: {str(e)}</p>
                    <a href="/">刷新页面</a>
                </body>
                </html>
                """, 500
        
        @self.app.route('/video_feed')
        def video_feed():
            """视频流"""
            return Response(self._generate_frames(),
                          mimetype='multipart/x-mixed-replace; boundary=frame')
        
        # 注册API路由
        register_api_routes(self.app, self)
    
    def _generate_frames(self):
        """生成视频帧"""
        while True:
            if self.camera is None or not self.camera.isOpened():
                break
            
            success, frame = self.camera.read()
            if not success:
                logger.warning("无法读取摄像头帧")
                break
            
            # 更新性能监控
            self.performance_monitor.update_frame()
            
            # 人脸检测
            face_boxes, inference_time, face_count = self.model.detect_faces(frame)
            
            # 更新数据存储
            self.data_store.update_face_detection(face_boxes, inference_time)
            
            # 绘制检测结果（传递追踪状态）
            result_frame = self.model.draw_detections(frame, face_boxes,
                                                    draw_center=True,
                                                    tracking_enabled=self.tracking_enabled)
            
            # 处理追踪逻辑
            if self.tracking_enabled and face_boxes and self.gimbal_controller and self.coord_calculator:
                self._process_tracking(face_boxes, result_frame.shape)
            
            # 更新云台状态
            if self.gimbal_controller:
                pan, tilt = self.gimbal_controller.get_current_angles()
                self.data_store.update_gimbal_status(
                    self.gimbal_controller.connected, pan, tilt
                )
            
            # 更新系统状态
            perf_stats = self.performance_monitor.get_stats()
            self.data_store.update_system_status(
                perf_stats['current_fps'],
                perf_stats['total_frames'],
                perf_stats['uptime']
            )
            
            # 编码帧
            ret, buffer = cv2.imencode('.jpg', result_frame)
            if ret:
                frame_bytes = buffer.tobytes()
                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
    
    def _process_tracking(self, face_boxes: list, frame_shape: tuple):
        """处理追踪逻辑"""
        if not face_boxes:
            return

        # 更新坐标计算器的目标信息
        if self.coord_calculator:
            # 将face_boxes转换为原有格式的bboxes
            bboxes = []
            scores = []
            for box in face_boxes:
                # face_boxes格式: [x1, y1, x2, y2]
                bboxes.append(box)
                scores.append(0.9)  # 假设置信度为0.9

            # 更新目标信息并获取最优目标
            target_id, target_bbox = self.coord_calculator.update_targets(bboxes, scores)

            if target_bbox is not None:
                # 计算偏移
                offset_x, offset_y, distance = self.coord_calculator.calculate_offset(target_bbox)

                # 更新追踪状态
                target_center = self.model.get_face_center(target_bbox)
                self.data_store.update_tracking_status(
                    True, target_id, target_center, (offset_x, offset_y)
                )

                logger.debug(f"追踪目标更新: ID={target_id}, 偏移=({offset_x:.1f}, {offset_y:.1f}), 距离={distance:.1f}")
            else:
                # 没有有效目标
                self.data_store.update_tracking_status(False, None, None, (0, 0))
    
    def start_tracking(self, target_id: Optional[int] = None) -> bool:
        """启动追踪"""
        if not self.gimbal_controller or not self.gimbal_controller.connected:
            logger.warning("云台未连接，无法启动追踪")
            return False

        if not self.coord_calculator:
            logger.warning("坐标计算器未初始化，无法启动追踪")
            return False

        self.tracking_enabled = True
        self.tracking_target_id = target_id

        # 启动云台自动追踪，传递坐标计算器
        success = self.gimbal_controller.start_auto_tracking(self.coord_calculator)
        if success:
            logger.info(f"追踪已启动，目标ID: {target_id}")
        else:
            self.tracking_enabled = False
            logger.error("启动云台自动追踪失败")

        return success
    
    def stop_tracking(self) -> bool:
        """停止追踪"""
        self.tracking_enabled = False
        self.tracking_target_id = None
        
        # 停止云台自动追踪
        if self.gimbal_controller:
            success = self.gimbal_controller.stop_auto_tracking()
            if success:
                logger.info("追踪已停止")
            return success
        
        return True
    
    def get_data_store(self) -> DataStore:
        """获取数据存储实例"""
        return self.data_store
    
    def get_gimbal_controller(self) -> Optional[GimbalController]:
        """获取云台控制器实例"""
        return self.gimbal_controller
    
    def run(self):
        """运行Web服务"""
        try:
            self.running = True
            host = self.config.web.host
            port = self.config.web.port
            debug = self.config.web.debug

            logger.info(f"Web服务启动: http://{host}:{port}/")

            # 使用Werkzeug的开发服务器，支持优雅关闭
            from werkzeug.serving import make_server

            self.server = make_server(
                host=host,
                port=port,
                app=self.app,
                threaded=self.config.web.threaded
            )

            # 启动服务器
            self.server.serve_forever()

        except Exception as e:
            logger.error(f"Web服务运行错误: {e}")
            raise
        finally:
            self.stop()
    
    def stop(self):
        """停止Web服务"""
        logger.info("正在停止Web服务...")
        self.running = False

        try:
            # 停止服务器
            if hasattr(self, 'server') and self.server:
                logger.info("正在关闭Web服务器...")
                self.server.shutdown()

            # 停止追踪
            if self.tracking_enabled:
                self.stop_tracking()

            # 断开云台连接
            if self.gimbal_controller:
                self.gimbal_controller.disconnect()

            # 释放摄像头
            if self.camera and self.camera.isOpened():
                self.camera.release()
                logger.info("摄像头已释放")

            logger.info("Web服务已停止")

        except Exception as e:
            logger.error(f"停止Web服务时出错: {e}")
